package com.bulls.dsp.service.impl;

import com.bulls.dsp.bean.mybatis.Ader;
import com.bulls.dsp.bean.mybatis.Order;
import com.bulls.dsp.bean.mybatis.Slot;
import com.bulls.dsp.common.Constant;
import com.bulls.dsp.common.PageInfo;
import com.bulls.dsp.bean.enums.*;
import com.bulls.dsp.exception.DuplicateException;
import com.bulls.dsp.exception.NoSuchAderException;
import com.bulls.dsp.exception.UnknownTypeException;
import com.bulls.dsp.mapper.AderMapper;
import com.bulls.dsp.mapper.OrderMapper;
import com.bulls.dsp.mapper.SlotMapper;
import com.bulls.dsp.service.IOrderService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;

@Service
@Transactional
public class OrderServiceImpl implements IOrderService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private AderMapper aderMapper;

    @Resource
    private SlotMapper slotMapper;

    @Override
    public void insertOrUpdate(Order order) {

        this.checkNameDuplicate(order);
        this.convertEnumsValue2Code(order);


        if (order.getId() == null) {
            orderMapper.insert(order);
        } else {
            orderMapper.update(order);
        }
    }

    @Override
    @Transactional(readOnly = true)
    public PageInfo<?> findAllByIfNotNull(String name, int page, int size) {

        String nameForLike = StringUtils.isEmpty(name) ? name : "%" + name.trim() + "%";
        List<Order> orders = orderMapper.getOrders(nameForLike, page, size);

        this.convertEnumsCode2Value(orders);
        this.putExactMatchFirst(orders, name);

        int totalCount = orderMapper.getOrdersCount(name);

        return PageInfo.builder()
                .totalElements(totalCount)
                .number(page)
                .size(size)
                .content(orders)
                .build();
    }

    private void convertEnumsValue2Code(Order order) {
        order.setAderId(
                Optional.ofNullable(order.getAderName())
                        .map(n -> aderMapper.getAderByName(n))
                        .map(Ader::getId)
                        .orElseThrow(NoSuchAderException::new)
        );

        order.setSlotId(
                Optional.ofNullable(order.getSlotName())
                        .map(name -> slotMapper.getSlotByName(name))
                        .map(Slot::getId)
                        .orElseThrow(UnknownTypeException::new)
        );

        order.setCarouselType(
                Optional.ofNullable(order.getCarouselType())
                        .map(CarouselType::getByStringValue)
                        .map(CarouselType::getValue)
                        .map(String::valueOf)
                        .orElse(null)
        );

        order.setChannel(
                Optional.ofNullable(order.getChannel())
                        .map(Channel::getByStringValue)
                        .map(Channel::getValue)
                        .map(String::valueOf)
                        .orElse(null)
        );

        order.setOrderStatus(
                Optional.ofNullable(order.getOrderStatus())
                        .map(OrderStatus::getByStringValue)
                        .map(OrderStatus::getValue)
                        .map(String::valueOf)
                        .orElse(null)
        );

        order.setPicSize(
                Optional.ofNullable(order.getPicSize())
                        .map(PicSize::getByStringValue)
                        .map(PicSize::getValue)
                        .map(String::valueOf)
                        .orElse(null)
        );

        order.setSettlementType(
                Optional.ofNullable(order.getSettlementType())
                        .map(SettlementType::getByStringValue)
                        .map(SettlementType::getValue)
                        .map(String::valueOf)
                        .orElse(null)
        );

        order.setPos(
                Optional.ofNullable(order.getPos())
                        .map(Pos::getByStringValue)
                        .map(Pos::getValue)
                        .map(String::valueOf)
                        .orElse(null)
        );

        order.setStartDate(
                Optional.ofNullable(order.getDate())
                        .map(dates -> dates.get(0))
                        .orElse(null)
        );

        order.setEndDate(
                Optional.ofNullable(order.getDate())
                        .map(dates -> dates.get(1))
                        .orElse(null)
        );
    }

    private void convertEnumsCode2Value(List<Order> orders) {
        orders.forEach(order -> {

            List<Date> date = new ArrayList<>();
            Optional.ofNullable(order.getStartDate()).map(date::add);
            Optional.ofNullable(order.getEndDate()).map(date::add);

            order.setDate(date);

            order.setCarouselType(
                    Optional.ofNullable(order.getCarouselType())
                            .map(CarouselType::getByStringCode)
                            .map(CarouselType::getType)
                            .orElse(Constant.UNKNOWN)
            );

            order.setChannel(
                    Optional.ofNullable(order.getChannel())
                            .map(Channel::getByStringCode)
                            .map(Channel::getType)
                            .orElse(Constant.UNKNOWN)
            );

            order.setOrderStatus(
                    Optional.ofNullable(order.getOrderStatus())
                            .map(OrderStatus::getByStringCode)
                            .map(OrderStatus::getStatus)
                            .orElse(Constant.UNKNOWN)
            );

            order.setSettlementType(
                    Optional.ofNullable(order.getSettlementType())
                            .map(SettlementType::getByStringCode)
                            .map(SettlementType::getType)
                            .orElse(Constant.UNKNOWN)
            );

            order.setPos(
                    Optional.ofNullable(order.getPos())
                            .map(Pos::getByStringCode)
                            .map(Pos::getType)
                            .orElse(Constant.UNKNOWN)
            );

        });
    }

    private void checkNameDuplicate(Order order) {

        Order old = orderMapper.getOrderByName(order.getName());
        if (!(old == null || Objects.equals(old.getId(), order.getId()))) {
            throw new DuplicateException("订单名称重复,请重试");
        }

    }

    @SuppressWarnings("unchecked")
    private void putExactMatchFirst(List<Order> orders, String name) {

        if (name == null) {
            return;
        }

        for (int i = 0; i < orders.size(); i++) {
            if (orders.get(i).getName().equals(name)) {
                orders.set(i, orders.set(0, orders.get(i)));
            }
        }
    }

    @Override
    public Map<String, List<List<String>>> getEnumsList() {

        Map<String, List<List<String>>> result = new HashMap<>();
        result.put("slotName", this.getSlotIdNameList());
        result.put("settlementType", SettlementType.getCodeValueList());
        result.put("orderStatus", OrderStatus.getCodeValueList());
        result.put("carouselType", CarouselType.getCodeValueList());
        result.put("channel", Channel.getCodeValueList());
        result.put("pos", Pos.getCodeValueList());

        return result;
    }

    // 广告由枚举改为对广告位表
    private List<List<String>> getSlotIdNameList() {
        List<Slot> slots = slotMapper.getSlots();

        List<List<String>> lists = new ArrayList<>();
        slots.forEach(slot -> {
            List<String> strings = new ArrayList<>();
            strings.add(String.valueOf(slot.getId()));
            strings.add(slot.getName());
            lists.add(strings);
        });

        return lists;
    }


    @Override
    public void changeOrderStatus(Long id, String statusTo) {

        Order order = new Order();
        order.setId(id);
        order.setOrderStatus(statusTo);
        orderMapper.updateStatus(order);
    }

}
